#include "serializer/serializer.h"

#include <gtest/gtest.h>

#include <array>
#include <optional>
#include <string>
#include <tuple>
#include <utility>

using namespace serializer;

/**
 * 通用往返序列化
 * 参数:
 * - value 输入值
 * - options 序列化选项
 * 返回值: 反序列化结果
 */
template <typename T>
T
roundtrip_via_cpo(const T & value, const default_options & options)
{
    vector_writer writer;
    serialize(writer, value, options);
    vector_reader reader(writer.data());
    return deserialize_cpo(reader, options, type_tag<T>);
}

TEST(cpo_composite_types_test, pair_and_tuple_roundtrip)
{
    default_options options{};

    std::pair<int, std::string> pr{42, "life"};
    auto pr_out = roundtrip_via_cpo(pr, options);
    EXPECT_EQ(pr_out, pr);

    std::tuple<int, double, std::string> tp{7, 2.71828, "e"};
    auto tp_out = roundtrip_via_cpo(tp, options);
    EXPECT_EQ(std::get<0>(tp_out), std::get<0>(tp));
    EXPECT_DOUBLE_EQ(std::get<1>(tp_out), std::get<1>(tp));
    EXPECT_EQ(std::get<2>(tp_out), std::get<2>(tp));
}

TEST(cpo_composite_types_test, optional_roundtrip)
{
    default_options options{};

    std::optional<int> ov = 123;
    auto ov_out = roundtrip_via_cpo(ov, options);
    EXPECT_EQ(ov_out, ov);

    std::optional<int> onull = std::nullopt;
    auto onull_out = roundtrip_via_cpo(onull, options);
    EXPECT_EQ(onull_out, onull);
}

TEST(cpo_composite_types_test, array_roundtrip)
{
    default_options options{};

    std::array<std::string, 3> arr{"x", "y", "z"};
    auto arr_out = roundtrip_via_cpo(arr, options);
    EXPECT_EQ(arr_out, arr);
}